#![allow(unreachable_patterns)]

use libc::c_char;
use std::ffi::{CStr, CString};
use std::mem::transmute;

use crate::sys;
use crate::sys::SDL_Scancode;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Scancode {
    A = SDL_Scancode::SDL_SCANCODE_A as i32,
    B = SDL_Scancode::SDL_SCANCODE_B as i32,
    C = SDL_Scancode::SDL_SCANCODE_C as i32,
    D = SDL_Scancode::SDL_SCANCODE_D as i32,
    E = SDL_Scancode::SDL_SCANCODE_E as i32,
    F = SDL_Scancode::SDL_SCANCODE_F as i32,
    G = SDL_Scancode::SDL_SCANCODE_G as i32,
    H = SDL_Scancode::SDL_SCANCODE_H as i32,
    I = SDL_Scancode::SDL_SCANCODE_I as i32,
    J = SDL_Scancode::SDL_SCANCODE_J as i32,
    K = SDL_Scancode::SDL_SCANCODE_K as i32,
    L = SDL_Scancode::SDL_SCANCODE_L as i32,
    M = SDL_Scancode::SDL_SCANCODE_M as i32,
    N = SDL_Scancode::SDL_SCANCODE_N as i32,
    O = SDL_Scancode::SDL_SCANCODE_O as i32,
    P = SDL_Scancode::SDL_SCANCODE_P as i32,
    Q = SDL_Scancode::SDL_SCANCODE_Q as i32,
    R = SDL_Scancode::SDL_SCANCODE_R as i32,
    S = SDL_Scancode::SDL_SCANCODE_S as i32,
    T = SDL_Scancode::SDL_SCANCODE_T as i32,
    U = SDL_Scancode::SDL_SCANCODE_U as i32,
    V = SDL_Scancode::SDL_SCANCODE_V as i32,
    W = SDL_Scancode::SDL_SCANCODE_W as i32,
    X = SDL_Scancode::SDL_SCANCODE_X as i32,
    Y = SDL_Scancode::SDL_SCANCODE_Y as i32,
    Z = SDL_Scancode::SDL_SCANCODE_Z as i32,
    Num1 = SDL_Scancode::SDL_SCANCODE_1 as i32,
    Num2 = SDL_Scancode::SDL_SCANCODE_2 as i32,
    Num3 = SDL_Scancode::SDL_SCANCODE_3 as i32,
    Num4 = SDL_Scancode::SDL_SCANCODE_4 as i32,
    Num5 = SDL_Scancode::SDL_SCANCODE_5 as i32,
    Num6 = SDL_Scancode::SDL_SCANCODE_6 as i32,
    Num7 = SDL_Scancode::SDL_SCANCODE_7 as i32,
    Num8 = SDL_Scancode::SDL_SCANCODE_8 as i32,
    Num9 = SDL_Scancode::SDL_SCANCODE_9 as i32,
    Num0 = SDL_Scancode::SDL_SCANCODE_0 as i32,
    Return = SDL_Scancode::SDL_SCANCODE_RETURN as i32,
    Escape = SDL_Scancode::SDL_SCANCODE_ESCAPE as i32,
    Backspace = SDL_Scancode::SDL_SCANCODE_BACKSPACE as i32,
    Tab = SDL_Scancode::SDL_SCANCODE_TAB as i32,
    Space = SDL_Scancode::SDL_SCANCODE_SPACE as i32,
    Minus = SDL_Scancode::SDL_SCANCODE_MINUS as i32,
    Equals = SDL_Scancode::SDL_SCANCODE_EQUALS as i32,
    LeftBracket = SDL_Scancode::SDL_SCANCODE_LEFTBRACKET as i32,
    RightBracket = SDL_Scancode::SDL_SCANCODE_RIGHTBRACKET as i32,
    Backslash = SDL_Scancode::SDL_SCANCODE_BACKSLASH as i32,
    NonUsHash = SDL_Scancode::SDL_SCANCODE_NONUSHASH as i32,
    Semicolon = SDL_Scancode::SDL_SCANCODE_SEMICOLON as i32,
    Apostrophe = SDL_Scancode::SDL_SCANCODE_APOSTROPHE as i32,
    Grave = SDL_Scancode::SDL_SCANCODE_GRAVE as i32,
    Comma = SDL_Scancode::SDL_SCANCODE_COMMA as i32,
    Period = SDL_Scancode::SDL_SCANCODE_PERIOD as i32,
    Slash = SDL_Scancode::SDL_SCANCODE_SLASH as i32,
    CapsLock = SDL_Scancode::SDL_SCANCODE_CAPSLOCK as i32,
    F1 = SDL_Scancode::SDL_SCANCODE_F1 as i32,
    F2 = SDL_Scancode::SDL_SCANCODE_F2 as i32,
    F3 = SDL_Scancode::SDL_SCANCODE_F3 as i32,
    F4 = SDL_Scancode::SDL_SCANCODE_F4 as i32,
    F5 = SDL_Scancode::SDL_SCANCODE_F5 as i32,
    F6 = SDL_Scancode::SDL_SCANCODE_F6 as i32,
    F7 = SDL_Scancode::SDL_SCANCODE_F7 as i32,
    F8 = SDL_Scancode::SDL_SCANCODE_F8 as i32,
    F9 = SDL_Scancode::SDL_SCANCODE_F9 as i32,
    F10 = SDL_Scancode::SDL_SCANCODE_F10 as i32,
    F11 = SDL_Scancode::SDL_SCANCODE_F11 as i32,
    F12 = SDL_Scancode::SDL_SCANCODE_F12 as i32,
    PrintScreen = SDL_Scancode::SDL_SCANCODE_PRINTSCREEN as i32,
    ScrollLock = SDL_Scancode::SDL_SCANCODE_SCROLLLOCK as i32,
    Pause = SDL_Scancode::SDL_SCANCODE_PAUSE as i32,
    Insert = SDL_Scancode::SDL_SCANCODE_INSERT as i32,
    Home = SDL_Scancode::SDL_SCANCODE_HOME as i32,
    PageUp = SDL_Scancode::SDL_SCANCODE_PAGEUP as i32,
    Delete = SDL_Scancode::SDL_SCANCODE_DELETE as i32,
    End = SDL_Scancode::SDL_SCANCODE_END as i32,
    PageDown = SDL_Scancode::SDL_SCANCODE_PAGEDOWN as i32,
    Right = SDL_Scancode::SDL_SCANCODE_RIGHT as i32,
    Left = SDL_Scancode::SDL_SCANCODE_LEFT as i32,
    Down = SDL_Scancode::SDL_SCANCODE_DOWN as i32,
    Up = SDL_Scancode::SDL_SCANCODE_UP as i32,
    NumLockClear = SDL_Scancode::SDL_SCANCODE_NUMLOCKCLEAR as i32,
    KpDivide = SDL_Scancode::SDL_SCANCODE_KP_DIVIDE as i32,
    KpMultiply = SDL_Scancode::SDL_SCANCODE_KP_MULTIPLY as i32,
    KpMinus = SDL_Scancode::SDL_SCANCODE_KP_MINUS as i32,
    KpPlus = SDL_Scancode::SDL_SCANCODE_KP_PLUS as i32,
    KpEnter = SDL_Scancode::SDL_SCANCODE_KP_ENTER as i32,
    Kp1 = SDL_Scancode::SDL_SCANCODE_KP_1 as i32,
    Kp2 = SDL_Scancode::SDL_SCANCODE_KP_2 as i32,
    Kp3 = SDL_Scancode::SDL_SCANCODE_KP_3 as i32,
    Kp4 = SDL_Scancode::SDL_SCANCODE_KP_4 as i32,
    Kp5 = SDL_Scancode::SDL_SCANCODE_KP_5 as i32,
    Kp6 = SDL_Scancode::SDL_SCANCODE_KP_6 as i32,
    Kp7 = SDL_Scancode::SDL_SCANCODE_KP_7 as i32,
    Kp8 = SDL_Scancode::SDL_SCANCODE_KP_8 as i32,
    Kp9 = SDL_Scancode::SDL_SCANCODE_KP_9 as i32,
    Kp0 = SDL_Scancode::SDL_SCANCODE_KP_0 as i32,
    KpPeriod = SDL_Scancode::SDL_SCANCODE_KP_PERIOD as i32,
    NonUsBackslash = SDL_Scancode::SDL_SCANCODE_NONUSBACKSLASH as i32,
    Application = SDL_Scancode::SDL_SCANCODE_APPLICATION as i32,
    Power = SDL_Scancode::SDL_SCANCODE_POWER as i32,
    KpEquals = SDL_Scancode::SDL_SCANCODE_KP_EQUALS as i32,
    F13 = SDL_Scancode::SDL_SCANCODE_F13 as i32,
    F14 = SDL_Scancode::SDL_SCANCODE_F14 as i32,
    F15 = SDL_Scancode::SDL_SCANCODE_F15 as i32,
    F16 = SDL_Scancode::SDL_SCANCODE_F16 as i32,
    F17 = SDL_Scancode::SDL_SCANCODE_F17 as i32,
    F18 = SDL_Scancode::SDL_SCANCODE_F18 as i32,
    F19 = SDL_Scancode::SDL_SCANCODE_F19 as i32,
    F20 = SDL_Scancode::SDL_SCANCODE_F20 as i32,
    F21 = SDL_Scancode::SDL_SCANCODE_F21 as i32,
    F22 = SDL_Scancode::SDL_SCANCODE_F22 as i32,
    F23 = SDL_Scancode::SDL_SCANCODE_F23 as i32,
    F24 = SDL_Scancode::SDL_SCANCODE_F24 as i32,
    Execute = SDL_Scancode::SDL_SCANCODE_EXECUTE as i32,
    Help = SDL_Scancode::SDL_SCANCODE_HELP as i32,
    Menu = SDL_Scancode::SDL_SCANCODE_MENU as i32,
    Select = SDL_Scancode::SDL_SCANCODE_SELECT as i32,
    Stop = SDL_Scancode::SDL_SCANCODE_STOP as i32,
    Again = SDL_Scancode::SDL_SCANCODE_AGAIN as i32,
    Undo = SDL_Scancode::SDL_SCANCODE_UNDO as i32,
    Cut = SDL_Scancode::SDL_SCANCODE_CUT as i32,
    Copy = SDL_Scancode::SDL_SCANCODE_COPY as i32,
    Paste = SDL_Scancode::SDL_SCANCODE_PASTE as i32,
    Find = SDL_Scancode::SDL_SCANCODE_FIND as i32,
    Mute = SDL_Scancode::SDL_SCANCODE_MUTE as i32,
    VolumeUp = SDL_Scancode::SDL_SCANCODE_VOLUMEUP as i32,
    VolumeDown = SDL_Scancode::SDL_SCANCODE_VOLUMEDOWN as i32,
    KpComma = SDL_Scancode::SDL_SCANCODE_KP_COMMA as i32,
    KpEqualsAS400 = SDL_Scancode::SDL_SCANCODE_KP_EQUALSAS400 as i32,
    International1 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL1 as i32,
    International2 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL2 as i32,
    International3 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL3 as i32,
    International4 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL4 as i32,
    International5 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL5 as i32,
    International6 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL6 as i32,
    International7 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL7 as i32,
    International8 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL8 as i32,
    International9 = SDL_Scancode::SDL_SCANCODE_INTERNATIONAL9 as i32,
    Lang1 = SDL_Scancode::SDL_SCANCODE_LANG1 as i32,
    Lang2 = SDL_Scancode::SDL_SCANCODE_LANG2 as i32,
    Lang3 = SDL_Scancode::SDL_SCANCODE_LANG3 as i32,
    Lang4 = SDL_Scancode::SDL_SCANCODE_LANG4 as i32,
    Lang5 = SDL_Scancode::SDL_SCANCODE_LANG5 as i32,
    Lang6 = SDL_Scancode::SDL_SCANCODE_LANG6 as i32,
    Lang7 = SDL_Scancode::SDL_SCANCODE_LANG7 as i32,
    Lang8 = SDL_Scancode::SDL_SCANCODE_LANG8 as i32,
    Lang9 = SDL_Scancode::SDL_SCANCODE_LANG9 as i32,
    AltErase = SDL_Scancode::SDL_SCANCODE_ALTERASE as i32,
    SysReq = SDL_Scancode::SDL_SCANCODE_SYSREQ as i32,
    Cancel = SDL_Scancode::SDL_SCANCODE_CANCEL as i32,
    Clear = SDL_Scancode::SDL_SCANCODE_CLEAR as i32,
    Prior = SDL_Scancode::SDL_SCANCODE_PRIOR as i32,
    Return2 = SDL_Scancode::SDL_SCANCODE_RETURN2 as i32,
    Separator = SDL_Scancode::SDL_SCANCODE_SEPARATOR as i32,
    Out = SDL_Scancode::SDL_SCANCODE_OUT as i32,
    Oper = SDL_Scancode::SDL_SCANCODE_OPER as i32,
    ClearAgain = SDL_Scancode::SDL_SCANCODE_CLEARAGAIN as i32,
    CrSel = SDL_Scancode::SDL_SCANCODE_CRSEL as i32,
    ExSel = SDL_Scancode::SDL_SCANCODE_EXSEL as i32,
    Kp00 = SDL_Scancode::SDL_SCANCODE_KP_00 as i32,
    Kp000 = SDL_Scancode::SDL_SCANCODE_KP_000 as i32,
    ThousandsSeparator = SDL_Scancode::SDL_SCANCODE_THOUSANDSSEPARATOR as i32,
    DecimalSeparator = SDL_Scancode::SDL_SCANCODE_DECIMALSEPARATOR as i32,
    CurrencyUnit = SDL_Scancode::SDL_SCANCODE_CURRENCYUNIT as i32,
    CurrencySubUnit = SDL_Scancode::SDL_SCANCODE_CURRENCYSUBUNIT as i32,
    KpLeftParen = SDL_Scancode::SDL_SCANCODE_KP_LEFTPAREN as i32,
    KpRightParen = SDL_Scancode::SDL_SCANCODE_KP_RIGHTPAREN as i32,
    KpLeftBrace = SDL_Scancode::SDL_SCANCODE_KP_LEFTBRACE as i32,
    KpRightBrace = SDL_Scancode::SDL_SCANCODE_KP_RIGHTBRACE as i32,
    KpTab = SDL_Scancode::SDL_SCANCODE_KP_TAB as i32,
    KpBackspace = SDL_Scancode::SDL_SCANCODE_KP_BACKSPACE as i32,
    KpA = SDL_Scancode::SDL_SCANCODE_KP_A as i32,
    KpB = SDL_Scancode::SDL_SCANCODE_KP_B as i32,
    KpC = SDL_Scancode::SDL_SCANCODE_KP_C as i32,
    KpD = SDL_Scancode::SDL_SCANCODE_KP_D as i32,
    KpE = SDL_Scancode::SDL_SCANCODE_KP_E as i32,
    KpF = SDL_Scancode::SDL_SCANCODE_KP_F as i32,
    KpXor = SDL_Scancode::SDL_SCANCODE_KP_XOR as i32,
    KpPower = SDL_Scancode::SDL_SCANCODE_KP_POWER as i32,
    KpPercent = SDL_Scancode::SDL_SCANCODE_KP_PERCENT as i32,
    KpLess = SDL_Scancode::SDL_SCANCODE_KP_LESS as i32,
    KpGreater = SDL_Scancode::SDL_SCANCODE_KP_GREATER as i32,
    KpAmpersand = SDL_Scancode::SDL_SCANCODE_KP_AMPERSAND as i32,
    KpDblAmpersand = SDL_Scancode::SDL_SCANCODE_KP_DBLAMPERSAND as i32,
    KpVerticalBar = SDL_Scancode::SDL_SCANCODE_KP_VERTICALBAR as i32,
    KpDblVerticalBar = SDL_Scancode::SDL_SCANCODE_KP_DBLVERTICALBAR as i32,
    KpColon = SDL_Scancode::SDL_SCANCODE_KP_COLON as i32,
    KpHash = SDL_Scancode::SDL_SCANCODE_KP_HASH as i32,
    KpSpace = SDL_Scancode::SDL_SCANCODE_KP_SPACE as i32,
    KpAt = SDL_Scancode::SDL_SCANCODE_KP_AT as i32,
    KpExclam = SDL_Scancode::SDL_SCANCODE_KP_EXCLAM as i32,
    KpMemStore = SDL_Scancode::SDL_SCANCODE_KP_MEMSTORE as i32,
    KpMemRecall = SDL_Scancode::SDL_SCANCODE_KP_MEMRECALL as i32,
    KpMemClear = SDL_Scancode::SDL_SCANCODE_KP_MEMCLEAR as i32,
    KpMemAdd = SDL_Scancode::SDL_SCANCODE_KP_MEMADD as i32,
    KpMemSubtract = SDL_Scancode::SDL_SCANCODE_KP_MEMSUBTRACT as i32,
    KpMemMultiply = SDL_Scancode::SDL_SCANCODE_KP_MEMMULTIPLY as i32,
    KpMemDivide = SDL_Scancode::SDL_SCANCODE_KP_MEMDIVIDE as i32,
    KpPlusMinus = SDL_Scancode::SDL_SCANCODE_KP_PLUSMINUS as i32,
    KpClear = SDL_Scancode::SDL_SCANCODE_KP_CLEAR as i32,
    KpClearEntry = SDL_Scancode::SDL_SCANCODE_KP_CLEARENTRY as i32,
    KpBinary = SDL_Scancode::SDL_SCANCODE_KP_BINARY as i32,
    KpOctal = SDL_Scancode::SDL_SCANCODE_KP_OCTAL as i32,
    KpDecimal = SDL_Scancode::SDL_SCANCODE_KP_DECIMAL as i32,
    KpHexadecimal = SDL_Scancode::SDL_SCANCODE_KP_HEXADECIMAL as i32,
    LCtrl = SDL_Scancode::SDL_SCANCODE_LCTRL as i32,
    LShift = SDL_Scancode::SDL_SCANCODE_LSHIFT as i32,
    LAlt = SDL_Scancode::SDL_SCANCODE_LALT as i32,
    LGui = SDL_Scancode::SDL_SCANCODE_LGUI as i32,
    RCtrl = SDL_Scancode::SDL_SCANCODE_RCTRL as i32,
    RShift = SDL_Scancode::SDL_SCANCODE_RSHIFT as i32,
    RAlt = SDL_Scancode::SDL_SCANCODE_RALT as i32,
    RGui = SDL_Scancode::SDL_SCANCODE_RGUI as i32,
    Mode = SDL_Scancode::SDL_SCANCODE_MODE as i32,
    AudioNext = SDL_Scancode::SDL_SCANCODE_AUDIONEXT as i32,
    AudioPrev = SDL_Scancode::SDL_SCANCODE_AUDIOPREV as i32,
    AudioStop = SDL_Scancode::SDL_SCANCODE_AUDIOSTOP as i32,
    AudioPlay = SDL_Scancode::SDL_SCANCODE_AUDIOPLAY as i32,
    AudioMute = SDL_Scancode::SDL_SCANCODE_AUDIOMUTE as i32,
    MediaSelect = SDL_Scancode::SDL_SCANCODE_MEDIASELECT as i32,
    Www = SDL_Scancode::SDL_SCANCODE_WWW as i32,
    Mail = SDL_Scancode::SDL_SCANCODE_MAIL as i32,
    Calculator = SDL_Scancode::SDL_SCANCODE_CALCULATOR as i32,
    Computer = SDL_Scancode::SDL_SCANCODE_COMPUTER as i32,
    AcSearch = SDL_Scancode::SDL_SCANCODE_AC_SEARCH as i32,
    AcHome = SDL_Scancode::SDL_SCANCODE_AC_HOME as i32,
    AcBack = SDL_Scancode::SDL_SCANCODE_AC_BACK as i32,
    AcForward = SDL_Scancode::SDL_SCANCODE_AC_FORWARD as i32,
    AcStop = SDL_Scancode::SDL_SCANCODE_AC_STOP as i32,
    AcRefresh = SDL_Scancode::SDL_SCANCODE_AC_REFRESH as i32,
    AcBookmarks = SDL_Scancode::SDL_SCANCODE_AC_BOOKMARKS as i32,
    BrightnessDown = SDL_Scancode::SDL_SCANCODE_BRIGHTNESSDOWN as i32,
    BrightnessUp = SDL_Scancode::SDL_SCANCODE_BRIGHTNESSUP as i32,
    DisplaySwitch = SDL_Scancode::SDL_SCANCODE_DISPLAYSWITCH as i32,
    KbdIllumToggle = SDL_Scancode::SDL_SCANCODE_KBDILLUMTOGGLE as i32,
    KbdIllumDown = SDL_Scancode::SDL_SCANCODE_KBDILLUMDOWN as i32,
    KbdIllumUp = SDL_Scancode::SDL_SCANCODE_KBDILLUMUP as i32,
    Eject = SDL_Scancode::SDL_SCANCODE_EJECT as i32,
    Sleep = SDL_Scancode::SDL_SCANCODE_SLEEP as i32,
    App1 = SDL_Scancode::SDL_SCANCODE_APP1 as i32,
    App2 = SDL_Scancode::SDL_SCANCODE_APP2 as i32,
    Num = SDL_Scancode::SDL_NUM_SCANCODES as i32,
}

impl Scancode {
    pub fn from_i32(n: i32) -> Option<Scancode> {
        use self::SDL_Scancode::*;
        use self::Scancode::*;

        Some(match n {
            v if v == SDL_SCANCODE_A as i32 => A,
            v if v == SDL_SCANCODE_B as i32 => B,
            v if v == SDL_SCANCODE_C as i32 => C,
            v if v == SDL_SCANCODE_D as i32 => D,
            v if v == SDL_SCANCODE_E as i32 => E,
            v if v == SDL_SCANCODE_F as i32 => F,
            v if v == SDL_SCANCODE_G as i32 => G,
            v if v == SDL_SCANCODE_H as i32 => H,
            v if v == SDL_SCANCODE_I as i32 => I,
            v if v == SDL_SCANCODE_J as i32 => J,
            v if v == SDL_SCANCODE_K as i32 => K,
            v if v == SDL_SCANCODE_L as i32 => L,
            v if v == SDL_SCANCODE_M as i32 => M,
            v if v == SDL_SCANCODE_N as i32 => N,
            v if v == SDL_SCANCODE_O as i32 => O,
            v if v == SDL_SCANCODE_P as i32 => P,
            v if v == SDL_SCANCODE_Q as i32 => Q,
            v if v == SDL_SCANCODE_R as i32 => R,
            v if v == SDL_SCANCODE_S as i32 => S,
            v if v == SDL_SCANCODE_T as i32 => T,
            v if v == SDL_SCANCODE_U as i32 => U,
            v if v == SDL_SCANCODE_V as i32 => V,
            v if v == SDL_SCANCODE_W as i32 => W,
            v if v == SDL_SCANCODE_X as i32 => X,
            v if v == SDL_SCANCODE_Y as i32 => Y,
            v if v == SDL_SCANCODE_Z as i32 => Z,
            v if v == SDL_SCANCODE_1 as i32 => Num1,
            v if v == SDL_SCANCODE_2 as i32 => Num2,
            v if v == SDL_SCANCODE_3 as i32 => Num3,
            v if v == SDL_SCANCODE_4 as i32 => Num4,
            v if v == SDL_SCANCODE_5 as i32 => Num5,
            v if v == SDL_SCANCODE_6 as i32 => Num6,
            v if v == SDL_SCANCODE_7 as i32 => Num7,
            v if v == SDL_SCANCODE_8 as i32 => Num8,
            v if v == SDL_SCANCODE_9 as i32 => Num9,
            v if v == SDL_SCANCODE_0 as i32 => Num0,
            v if v == SDL_SCANCODE_RETURN as i32 => Return,
            v if v == SDL_SCANCODE_ESCAPE as i32 => Escape,
            v if v == SDL_SCANCODE_BACKSPACE as i32 => Backspace,
            v if v == SDL_SCANCODE_TAB as i32 => Tab,
            v if v == SDL_SCANCODE_SPACE as i32 => Space,
            v if v == SDL_SCANCODE_MINUS as i32 => Minus,
            v if v == SDL_SCANCODE_EQUALS as i32 => Equals,
            v if v == SDL_SCANCODE_LEFTBRACKET as i32 => LeftBracket,
            v if v == SDL_SCANCODE_RIGHTBRACKET as i32 => RightBracket,
            v if v == SDL_SCANCODE_BACKSLASH as i32 => Backslash,
            v if v == SDL_SCANCODE_NONUSHASH as i32 => NonUsHash,
            v if v == SDL_SCANCODE_SEMICOLON as i32 => Semicolon,
            v if v == SDL_SCANCODE_APOSTROPHE as i32 => Apostrophe,
            v if v == SDL_SCANCODE_GRAVE as i32 => Grave,
            v if v == SDL_SCANCODE_COMMA as i32 => Comma,
            v if v == SDL_SCANCODE_PERIOD as i32 => Period,
            v if v == SDL_SCANCODE_SLASH as i32 => Slash,
            v if v == SDL_SCANCODE_CAPSLOCK as i32 => CapsLock,
            v if v == SDL_SCANCODE_F1 as i32 => F1,
            v if v == SDL_SCANCODE_F2 as i32 => F2,
            v if v == SDL_SCANCODE_F3 as i32 => F3,
            v if v == SDL_SCANCODE_F4 as i32 => F4,
            v if v == SDL_SCANCODE_F5 as i32 => F5,
            v if v == SDL_SCANCODE_F6 as i32 => F6,
            v if v == SDL_SCANCODE_F7 as i32 => F7,
            v if v == SDL_SCANCODE_F8 as i32 => F8,
            v if v == SDL_SCANCODE_F9 as i32 => F9,
            v if v == SDL_SCANCODE_F10 as i32 => F10,
            v if v == SDL_SCANCODE_F11 as i32 => F11,
            v if v == SDL_SCANCODE_F12 as i32 => F12,
            v if v == SDL_SCANCODE_PRINTSCREEN as i32 => PrintScreen,
            v if v == SDL_SCANCODE_SCROLLLOCK as i32 => ScrollLock,
            v if v == SDL_SCANCODE_PAUSE as i32 => Pause,
            v if v == SDL_SCANCODE_INSERT as i32 => Insert,
            v if v == SDL_SCANCODE_HOME as i32 => Home,
            v if v == SDL_SCANCODE_PAGEUP as i32 => PageUp,
            v if v == SDL_SCANCODE_DELETE as i32 => Delete,
            v if v == SDL_SCANCODE_END as i32 => End,
            v if v == SDL_SCANCODE_PAGEDOWN as i32 => PageDown,
            v if v == SDL_SCANCODE_RIGHT as i32 => Right,
            v if v == SDL_SCANCODE_LEFT as i32 => Left,
            v if v == SDL_SCANCODE_DOWN as i32 => Down,
            v if v == SDL_SCANCODE_UP as i32 => Up,
            v if v == SDL_SCANCODE_NUMLOCKCLEAR as i32 => NumLockClear,
            v if v == SDL_SCANCODE_KP_DIVIDE as i32 => KpDivide,
            v if v == SDL_SCANCODE_KP_MULTIPLY as i32 => KpMultiply,
            v if v == SDL_SCANCODE_KP_MINUS as i32 => KpMinus,
            v if v == SDL_SCANCODE_KP_PLUS as i32 => KpPlus,
            v if v == SDL_SCANCODE_KP_ENTER as i32 => KpEnter,
            v if v == SDL_SCANCODE_KP_1 as i32 => Kp1,
            v if v == SDL_SCANCODE_KP_2 as i32 => Kp2,
            v if v == SDL_SCANCODE_KP_3 as i32 => Kp3,
            v if v == SDL_SCANCODE_KP_4 as i32 => Kp4,
            v if v == SDL_SCANCODE_KP_5 as i32 => Kp5,
            v if v == SDL_SCANCODE_KP_6 as i32 => Kp6,
            v if v == SDL_SCANCODE_KP_7 as i32 => Kp7,
            v if v == SDL_SCANCODE_KP_8 as i32 => Kp8,
            v if v == SDL_SCANCODE_KP_9 as i32 => Kp9,
            v if v == SDL_SCANCODE_KP_0 as i32 => Kp0,
            v if v == SDL_SCANCODE_KP_PERIOD as i32 => KpPeriod,
            v if v == SDL_SCANCODE_NONUSBACKSLASH as i32 => NonUsBackslash,
            v if v == SDL_SCANCODE_APPLICATION as i32 => Application,
            v if v == SDL_SCANCODE_POWER as i32 => Power,
            v if v == SDL_SCANCODE_KP_EQUALS as i32 => KpEquals,
            v if v == SDL_SCANCODE_F13 as i32 => F13,
            v if v == SDL_SCANCODE_F14 as i32 => F14,
            v if v == SDL_SCANCODE_F15 as i32 => F15,
            v if v == SDL_SCANCODE_F16 as i32 => F16,
            v if v == SDL_SCANCODE_F17 as i32 => F17,
            v if v == SDL_SCANCODE_F18 as i32 => F18,
            v if v == SDL_SCANCODE_F19 as i32 => F19,
            v if v == SDL_SCANCODE_F20 as i32 => F20,
            v if v == SDL_SCANCODE_F21 as i32 => F21,
            v if v == SDL_SCANCODE_F22 as i32 => F22,
            v if v == SDL_SCANCODE_F23 as i32 => F23,
            v if v == SDL_SCANCODE_F24 as i32 => F24,
            v if v == SDL_SCANCODE_EXECUTE as i32 => Execute,
            v if v == SDL_SCANCODE_HELP as i32 => Help,
            v if v == SDL_SCANCODE_MENU as i32 => Menu,
            v if v == SDL_SCANCODE_SELECT as i32 => Select,
            v if v == SDL_SCANCODE_STOP as i32 => Stop,
            v if v == SDL_SCANCODE_AGAIN as i32 => Again,
            v if v == SDL_SCANCODE_UNDO as i32 => Undo,
            v if v == SDL_SCANCODE_CUT as i32 => Cut,
            v if v == SDL_SCANCODE_COPY as i32 => Copy,
            v if v == SDL_SCANCODE_PASTE as i32 => Paste,
            v if v == SDL_SCANCODE_FIND as i32 => Find,
            v if v == SDL_SCANCODE_MUTE as i32 => Mute,
            v if v == SDL_SCANCODE_VOLUMEUP as i32 => VolumeUp,
            v if v == SDL_SCANCODE_VOLUMEDOWN as i32 => VolumeDown,
            v if v == SDL_SCANCODE_KP_COMMA as i32 => KpComma,
            v if v == SDL_SCANCODE_KP_EQUALSAS400 as i32 => KpEqualsAS400,
            v if v == SDL_SCANCODE_INTERNATIONAL1 as i32 => International1,
            v if v == SDL_SCANCODE_INTERNATIONAL2 as i32 => International2,
            v if v == SDL_SCANCODE_INTERNATIONAL3 as i32 => International3,
            v if v == SDL_SCANCODE_INTERNATIONAL4 as i32 => International4,
            v if v == SDL_SCANCODE_INTERNATIONAL5 as i32 => International5,
            v if v == SDL_SCANCODE_INTERNATIONAL6 as i32 => International6,
            v if v == SDL_SCANCODE_INTERNATIONAL7 as i32 => International7,
            v if v == SDL_SCANCODE_INTERNATIONAL8 as i32 => International8,
            v if v == SDL_SCANCODE_INTERNATIONAL9 as i32 => International9,
            v if v == SDL_SCANCODE_LANG1 as i32 => Lang1,
            v if v == SDL_SCANCODE_LANG2 as i32 => Lang2,
            v if v == SDL_SCANCODE_LANG3 as i32 => Lang3,
            v if v == SDL_SCANCODE_LANG4 as i32 => Lang4,
            v if v == SDL_SCANCODE_LANG5 as i32 => Lang5,
            v if v == SDL_SCANCODE_LANG6 as i32 => Lang6,
            v if v == SDL_SCANCODE_LANG7 as i32 => Lang7,
            v if v == SDL_SCANCODE_LANG8 as i32 => Lang8,
            v if v == SDL_SCANCODE_LANG9 as i32 => Lang9,
            v if v == SDL_SCANCODE_ALTERASE as i32 => AltErase,
            v if v == SDL_SCANCODE_SYSREQ as i32 => SysReq,
            v if v == SDL_SCANCODE_CANCEL as i32 => Cancel,
            v if v == SDL_SCANCODE_CLEAR as i32 => Clear,
            v if v == SDL_SCANCODE_PRIOR as i32 => Prior,
            v if v == SDL_SCANCODE_RETURN2 as i32 => Return2,
            v if v == SDL_SCANCODE_SEPARATOR as i32 => Separator,
            v if v == SDL_SCANCODE_OUT as i32 => Out,
            v if v == SDL_SCANCODE_OPER as i32 => Oper,
            v if v == SDL_SCANCODE_CLEARAGAIN as i32 => ClearAgain,
            v if v == SDL_SCANCODE_CRSEL as i32 => CrSel,
            v if v == SDL_SCANCODE_EXSEL as i32 => ExSel,
            v if v == SDL_SCANCODE_KP_00 as i32 => Kp00,
            v if v == SDL_SCANCODE_KP_000 as i32 => Kp000,
            v if v == SDL_SCANCODE_THOUSANDSSEPARATOR as i32 => ThousandsSeparator,
            v if v == SDL_SCANCODE_DECIMALSEPARATOR as i32 => DecimalSeparator,
            v if v == SDL_SCANCODE_CURRENCYUNIT as i32 => CurrencyUnit,
            v if v == SDL_SCANCODE_CURRENCYSUBUNIT as i32 => CurrencySubUnit,
            v if v == SDL_SCANCODE_KP_LEFTPAREN as i32 => KpLeftParen,
            v if v == SDL_SCANCODE_KP_RIGHTPAREN as i32 => KpRightParen,
            v if v == SDL_SCANCODE_KP_LEFTBRACE as i32 => KpLeftBrace,
            v if v == SDL_SCANCODE_KP_RIGHTBRACE as i32 => KpRightBrace,
            v if v == SDL_SCANCODE_KP_TAB as i32 => KpTab,
            v if v == SDL_SCANCODE_KP_BACKSPACE as i32 => KpBackspace,
            v if v == SDL_SCANCODE_KP_A as i32 => KpA,
            v if v == SDL_SCANCODE_KP_B as i32 => KpB,
            v if v == SDL_SCANCODE_KP_C as i32 => KpC,
            v if v == SDL_SCANCODE_KP_D as i32 => KpD,
            v if v == SDL_SCANCODE_KP_E as i32 => KpE,
            v if v == SDL_SCANCODE_KP_F as i32 => KpF,
            v if v == SDL_SCANCODE_KP_XOR as i32 => KpXor,
            v if v == SDL_SCANCODE_KP_POWER as i32 => KpPower,
            v if v == SDL_SCANCODE_KP_PERCENT as i32 => KpPercent,
            v if v == SDL_SCANCODE_KP_LESS as i32 => KpLess,
            v if v == SDL_SCANCODE_KP_GREATER as i32 => KpGreater,
            v if v == SDL_SCANCODE_KP_AMPERSAND as i32 => KpAmpersand,
            v if v == SDL_SCANCODE_KP_DBLAMPERSAND as i32 => KpDblAmpersand,
            v if v == SDL_SCANCODE_KP_VERTICALBAR as i32 => KpVerticalBar,
            v if v == SDL_SCANCODE_KP_DBLVERTICALBAR as i32 => KpDblVerticalBar,
            v if v == SDL_SCANCODE_KP_COLON as i32 => KpColon,
            v if v == SDL_SCANCODE_KP_HASH as i32 => KpHash,
            v if v == SDL_SCANCODE_KP_SPACE as i32 => KpSpace,
            v if v == SDL_SCANCODE_KP_AT as i32 => KpAt,
            v if v == SDL_SCANCODE_KP_EXCLAM as i32 => KpExclam,
            v if v == SDL_SCANCODE_KP_MEMSTORE as i32 => KpMemStore,
            v if v == SDL_SCANCODE_KP_MEMRECALL as i32 => KpMemRecall,
            v if v == SDL_SCANCODE_KP_MEMCLEAR as i32 => KpMemClear,
            v if v == SDL_SCANCODE_KP_MEMADD as i32 => KpMemAdd,
            v if v == SDL_SCANCODE_KP_MEMSUBTRACT as i32 => KpMemSubtract,
            v if v == SDL_SCANCODE_KP_MEMMULTIPLY as i32 => KpMemMultiply,
            v if v == SDL_SCANCODE_KP_MEMDIVIDE as i32 => KpMemDivide,
            v if v == SDL_SCANCODE_KP_PLUSMINUS as i32 => KpPlusMinus,
            v if v == SDL_SCANCODE_KP_CLEAR as i32 => KpClear,
            v if v == SDL_SCANCODE_KP_CLEARENTRY as i32 => KpClearEntry,
            v if v == SDL_SCANCODE_KP_BINARY as i32 => KpBinary,
            v if v == SDL_SCANCODE_KP_OCTAL as i32 => KpOctal,
            v if v == SDL_SCANCODE_KP_DECIMAL as i32 => KpDecimal,
            v if v == SDL_SCANCODE_KP_HEXADECIMAL as i32 => KpHexadecimal,
            v if v == SDL_SCANCODE_LCTRL as i32 => LCtrl,
            v if v == SDL_SCANCODE_LSHIFT as i32 => LShift,
            v if v == SDL_SCANCODE_LALT as i32 => LAlt,
            v if v == SDL_SCANCODE_LGUI as i32 => LGui,
            v if v == SDL_SCANCODE_RCTRL as i32 => RCtrl,
            v if v == SDL_SCANCODE_RSHIFT as i32 => RShift,
            v if v == SDL_SCANCODE_RALT as i32 => RAlt,
            v if v == SDL_SCANCODE_RGUI as i32 => RGui,
            v if v == SDL_SCANCODE_MODE as i32 => Mode,
            v if v == SDL_SCANCODE_AUDIONEXT as i32 => AudioNext,
            v if v == SDL_SCANCODE_AUDIOPREV as i32 => AudioPrev,
            v if v == SDL_SCANCODE_AUDIOSTOP as i32 => AudioStop,
            v if v == SDL_SCANCODE_AUDIOPLAY as i32 => AudioPlay,
            v if v == SDL_SCANCODE_AUDIOMUTE as i32 => AudioMute,
            v if v == SDL_SCANCODE_MEDIASELECT as i32 => MediaSelect,
            v if v == SDL_SCANCODE_WWW as i32 => Www,
            v if v == SDL_SCANCODE_MAIL as i32 => Mail,
            v if v == SDL_SCANCODE_CALCULATOR as i32 => Calculator,
            v if v == SDL_SCANCODE_COMPUTER as i32 => Computer,
            v if v == SDL_SCANCODE_AC_SEARCH as i32 => AcSearch,
            v if v == SDL_SCANCODE_AC_HOME as i32 => AcHome,
            v if v == SDL_SCANCODE_AC_BACK as i32 => AcBack,
            v if v == SDL_SCANCODE_AC_FORWARD as i32 => AcForward,
            v if v == SDL_SCANCODE_AC_STOP as i32 => AcStop,
            v if v == SDL_SCANCODE_AC_REFRESH as i32 => AcRefresh,
            v if v == SDL_SCANCODE_AC_BOOKMARKS as i32 => AcBookmarks,
            v if v == SDL_SCANCODE_BRIGHTNESSDOWN as i32 => BrightnessDown,
            v if v == SDL_SCANCODE_BRIGHTNESSUP as i32 => BrightnessUp,
            v if v == SDL_SCANCODE_DISPLAYSWITCH as i32 => DisplaySwitch,
            v if v == SDL_SCANCODE_KBDILLUMTOGGLE as i32 => KbdIllumToggle,
            v if v == SDL_SCANCODE_KBDILLUMDOWN as i32 => KbdIllumDown,
            v if v == SDL_SCANCODE_KBDILLUMUP as i32 => KbdIllumUp,
            v if v == SDL_SCANCODE_EJECT as i32 => Eject,
            v if v == SDL_SCANCODE_SLEEP as i32 => Sleep,
            v if v == SDL_SCANCODE_APP1 as i32 => App1,
            v if v == SDL_SCANCODE_APP2 as i32 => App2,
            v if v == SDL_NUM_SCANCODES as i32 => Num,
            _ => return None,
        })
    }
}

use std::fmt;

impl fmt::Display for Scancode {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.name())
    }
}

use crate::keyboard::Keycode;

impl Scancode {
    /// Gets the scancode from a virtual key. Returns None if there is no corresponding scancode.
    #[doc(alias = "SDL_GetScancodeFromKey")]
    pub fn from_keycode(keycode: Keycode) -> Option<Scancode> {
        unsafe {
            match sys::SDL_GetScancodeFromKey(keycode.into()) {
                SDL_Scancode::SDL_SCANCODE_UNKNOWN => None,
                scancode_id => Scancode::from_i32(scancode_id as i32),
            }
        }
    }

    #[doc(alias = "SDL_GetScancodeFromName")]
    pub fn from_name(name: &str) -> Option<Scancode> {
        unsafe {
            match CString::new(name) {
                Ok(name) => match sys::SDL_GetScancodeFromName(name.as_ptr() as *const c_char) {
                    SDL_Scancode::SDL_SCANCODE_UNKNOWN => None,
                    scancode_id => Some(Scancode::from_i32(scancode_id as i32).unwrap()),
                },
                // string contains a nul byte - it won't match anything.
                Err(_) => None,
            }
        }
    }

    #[doc(alias = "SDL_GetScancodeName")]
    pub fn name(self) -> &'static str {
        // The name string pointer lives in static, read-only memory.
        // Knowing this, we can always return a string slice.
        unsafe {
            let buf = sys::SDL_GetScancodeName(transmute::<u32, SDL_Scancode>(self as u32));
            ::std::str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap()
        }
    }
}
